package com.netease.neliveplayer.playerkit.videoLoader;

import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.util.Pair;
import android.view.View;

import com.netease.neliveplayer.playerkit.common.log.LogUtil;
import com.netease.neliveplayer.playerkit.sdk.LivePlayerObserver;
import com.netease.neliveplayer.playerkit.sdk.PlayerManager;
import com.netease.neliveplayer.playerkit.sdk.VodPlayer;
import com.netease.neliveplayer.playerkit.sdk.VodPlayerObserver;
import com.netease.neliveplayer.playerkit.sdk.model.MediaInfo;
import com.netease.neliveplayer.playerkit.sdk.model.StateInfo;
import com.netease.neliveplayer.playerkit.sdk.model.VideoBufferStrategy;
import com.netease.neliveplayer.playerkit.sdk.model.VideoOptions;
import com.netease.neliveplayer.playerkit.sdk.model.VideoScaleMode;
import com.netease.neliveplayer.playerkit.sdk.view.AdvanceTextureView;
import com.netease.neliveplayer.proxy.gslb.NEGslbServerModel;
import com.netease.neliveplayer.sdk.NELivePlayer;
import com.netease.neliveplayer.sdk.model.PlayerBufferingStopStrategy;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


public class VideoLoaderImpl implements VideoLoader {
    private HashMap<String, Pair<Object,NEGslbServerModel>> glsbMp = new HashMap<>();
    private HashSet<String> keepSet = new HashSet<>();
    private ArrayList<playerInfo> playerList = new ArrayList<>();
    private ArrayList<VideoLoader.VideoInfo> videoListRecord;
    private String currentUrl;
    private String currentSubUrl;
    private String nextUrl;
    private AdvanceTextureView currentView;
    private String lastUrl;
    private final Object lock = new Object();
    private PlayerListener sink;
    private int mMode;
    private boolean isInScrollState = false;
    private Handler mhandler;
    private int videoIndex = 0;
    private ArrayList<ArrayList<String>> currentUrlList;
    LivePlayerObserver playerObserver;

    private VideoLoaderImpl() {

    }
    @Override
    public void init(Context context,int mode, VideoOptions options) {
        PlayerManager.init(context, null);
        mMode = mode;
        mhandler = new Handler();
        if(playerList.size() >= 6){
            return;
        }
        playerObserver = new VodPlayerObserver() {
            @Override
            public void onCurrentPlayProgress(long currentPosition, long duration, float percent, long cachedPosition) {
                if(sink != null && currentPosition > 1){
                    sink.onCurrentPlayProgress(currentPosition, duration, percent, cachedPosition);
                }
            }

            @Override
            public void onSeekCompleted() {

            }

            @Override
            public void onCompletion() {

            }

            @Override
            public void onAudioVideoUnsync() {

            }

            @Override
            public void onNetStateBad() {

            }

            @Override
            public void onDecryption(int ret) {

            }

            @Override
            public void onPreparing() {

            }

            @Override
            public void onPrepared(MediaInfo mediaInfo) {

            }

            @Override
            public void onError(int code, int extra) {

            }

            @Override
            public void onFirstVideoRendered() {

            }

            @Override
            public void onFirstAudioRendered() {

            }

            @Override
            public void onBufferingStart() {

            }

            @Override
            public void onBufferingEnd() {

            }

            @Override
            public void onBuffering(int percent) {

            }

            @Override
            public void onVideoDecoderOpen(int value) {

            }

            @Override
            public void onStateChanged(StateInfo stateInfo) {

            }

            @Override
            public void onHttpResponseInfo(int code, String header) {

            }
        };
        for(int i = 0;i < 6;i++) {
            VodPlayer player = PlayerManager.buildVodPlayer(context, "", options);
            player.setVideoLoaderSink(this);
            player.init();
            player.registerPlayerObserver(playerObserver, true);
            playerList.add(new playerInfo("", player));
        }
    }

    public void updateVideoPreLoad(int position){
        if (videoListRecord == null)
            return;
        VideoLoader.VideoInfo info = videoListRecord.get(position % videoListRecord.size());

        VideoLoader.VideoInfo linfo = videoListRecord.get(Math.max(0, (position - 1)) % videoListRecord.size());
        VideoLoader.VideoInfo ninfo = videoListRecord.get((position + 1) % videoListRecord.size());
        VideoLoader.VideoInfo nninfo = videoListRecord.get((position + 2) % videoListRecord.size());
        ArrayList<ArrayList<String>> urlList = new ArrayList<>(Arrays.asList(info.url, linfo.url, ninfo.url, nninfo.url));
        VideoLoaderImpl.getInstance().setLivePlayerURLList(urlList);
    }

    public void preloadUrl(ArrayList<VideoLoader.VideoInfo> videoList) {
        if(playerList.isEmpty() || playerList.get(0).player == null)
            return ;
        synchronized (lock) {
            videoListRecord = videoList;
            //首先对前6个url进行glsb预加载
            for (int i = 0; i < videoList.size() && i < 6; i++) {
                playerList.get(0).player.queryPreloadUrlResult(videoList.get(i).url.get(videoIndex), new GslbResultListener(videoList, videoList.get(i).url.get(videoIndex), 0));
            }
        }
    }
    public void preloadUrl(ArrayList<VideoLoader.VideoInfo> videoList, int from, int to) {
        if(playerList == null || playerList.isEmpty() || playerList.get(0) == null || playerList.get(0).player == null)
            return ;
        synchronized (lock) {
            LogUtil.info("[videoLoaderImpl]from:" + from + "to:" + to);
            //将from 到to的url放到预加载列表
            for (int i = from; i <= to; i++) {
                if (i > videoList.size()) {
                    return;
                }
                keepSet.add(videoList.get(i).url.get(videoIndex));
                playerList.get(0).player.queryPreloadUrlResult(videoList.get(i).url.get(videoIndex), new GslbResultListener(videoList, videoList.get(i).url.get(videoIndex), from));
            }

            //移除不在列表中的url
            ArrayList<String> url_delete = new ArrayList<>();
            Iterator<Map.Entry<String, Pair<Object, NEGslbServerModel>>> it_b = glsbMp.entrySet().iterator();
            while (it_b.hasNext()) {
                String key = it_b.next().getKey();
                if (!keepSet.contains(key)) {
                    it_b.remove();
                    url_delete.add(key);
                }
            }
            PlayerManager.removePreloadUrls(url_delete);
            keepSet.clear();
        }
    }
    @Override
    public void playResume() {
        if(currentView != null && isInScrollState){
            LogUtil.info("[videoLoaderImpl] playResume");
            stopAllRefresher();
            renderAndPlay(lastUrl, currentView);
            startAllRefresher();
        }
    }
    @Override
    public void playPause() {
        stopAllRefresher();
        if(currentUrl != null){
            for(int i = 0;i < playerList.size();i++) {
                if(playerList.get(i).url.equals(currentUrl)) {
                    synchronized (lock) {
                        LogUtil.info( "[videoLoaderImpl]stopPlay: url:" + currentUrl.substring(Math.max(currentUrl.length() - 8, 0)) + "player: " + i);
                        playerList.get(i).player.stopWithoutRelease();
                        playerList.get(i).player.setAutoPlay(false);
                        if (!glsbMp.containsKey(currentUrl)) {
                            playerList.get(i).player.queryPreloadUrlResult(currentUrl, new GslbResultListener(playerList.get(i).player, currentUrl));
                            LogUtil.info( "[videoLoaderImpl] queryPreloadUrl first url: " + currentUrl);
                        }else {
                            Object session = Objects.requireNonNull(glsbMp.get(currentUrl)).first;
                            NEGslbServerModel model = Objects.requireNonNull(glsbMp.get(currentUrl)).second;
                            playerList.get(i).player.switchWithGslbResult(session, model);
                        }
                    }
                    break;
                }
            }
        }
        clearUrl();
        startAllRefresher();
    }

    public void changeVideoSource(String source) {
        if (currentUrl != null) {
            for (int i = 0; i < playerList.size(); i++) {
                if (playerList.get(i).url.equals(currentUrl)) {
                    playerList.get(i).player.stopWithoutRelease();
                    currentSubUrl = source;
                    playerList.get(i).count = 0;
                    playerList.get(i).player.queryPreloadUrlResult(source, new GslbResultListener(playerList.get(i).player, source, true));
                    LogUtil.info("[videoLoaderImpl] queryPreloadUrl first url: " + source);
                    break;
                }
            }
        }
    }
    @Override
    public void registerPlayerListener(PlayerListener listener) {
        sink = listener;
    }
    @Override
    public void changeVideoSource(int index, boolean mark) {
        LogUtil.info("[videoLoaderImpl] switchVideoResolution");
        int currentIndex = 0;
        if (currentUrl != null) {
            for (int i = 0; i < playerList.size(); i++) {
                if(mark && !playerList.get(i).url.equals(currentUrl)){
                    playerList.get(i).player.stopWithoutRelease();
                    playerList.get(i).url = "";
                }
                if (playerList.get(i).url.equals(currentUrl)) {
                    if(index >= playerList.get(i).urlList.size())
                        return;
                    currentIndex = i;
                    playerList.get(i).player.stopWithoutRelease();
                    String dstUrl = playerList.get(i).urlList.get(index);
                    currentSubUrl = dstUrl;
                    playerList.get(i).count = 0;
                    playerList.get(i).player.queryPreloadUrlResult(dstUrl, new GslbResultListener(playerList.get(i).player, dstUrl, true));
                    LogUtil.info("[videoLoaderImpl] queryPreloadUrl first url: " + dstUrl);
                    break;
                }
            }
        }
        if(mark) {
            videoIndex = index;
            if(currentUrlList != null && currentUrl != null){
                stopAllRefresher();
                currentUrl = currentSubUrl;
                playerList.get(currentIndex).url = currentSubUrl;
                setLivePlayerURLList(currentUrlList);
                //打开所有定时器
                startAllRefresher();
            }
        }
    }
    public int renderAndPlay(String curl, AdvanceTextureView view){
        stopAllRefresher();
        int ret = renderAndPlayInternal(curl, view);
        startAllRefresher();
        return ret;
    }

    public void renderAndPlay(ArrayList<String> curlList, AdvanceTextureView view){
        String curl = curlList.get(videoIndex);
        renderAndPlayInternal(curl, view);
    }
    public int renderAndPlayInternal(String curl, AdvanceTextureView view){
        LogUtil.error( "[videoLoaderImpl]renderAndPlayInternal !");
        if(curl != null && curl.equals(currentUrl)){
            VideoLoaderImpl.getInstance().setupCanvas(view);
            LogUtil.info( "[videoLoaderImpl]url had render");
            return -1;
        }
        isInScrollState = true;
        LogUtil.info(  "[videoLoaderImpl]renderAndPlay  " + curl);
        synchronized (lock) {
            if (curl != null) {
                //切换当前播放地址
                lastUrl = currentUrl;
                currentUrl = curl;
                currentSubUrl = null;
                LogUtil.info("[videoLoaderImpl]change currenturl:" + currentUrl);
            }
            //暂停上一个
            if (lastUrl != null) {
                for (int i = 0; i < playerList.size(); i++) {
                    if (playerList.get(i).url.equals(lastUrl)) {
                        LogUtil.info( "[videoLoaderImpl]stop last url:" + lastUrl + " url: " + playerList.get(i).url.substring(Math.max(playerList.get(i).url.length() - 8, 0)));
                        playerList.get(i).player.stopWithoutRelease();
                        playerList.get(i).url = "";
                        break;
                    }
                }
            }
            //播放当前的
            if (currentUrl != null) {
                for (int i = 0; i < playerList.size(); i++) {
                    if (playerList.get(i).url.equals(currentUrl)) {
                        currentView = view;
                        showParentViews(view);
                        view.setVisibility(View.VISIBLE);
                        VideoLoaderImpl.getInstance().setupCanvas(view);
                        playerList.get(i).player.startWithoutInit();
                        playerList.get(i).count = 0;
                        LogUtil.info("[videoLoaderImpl] startWithoutInit current:" + currentUrl.substring(Math.max(currentUrl.length() - 8, 0)) + " player:" + i);
                        break;
                    }
                }
            }
        }
        return 0;
    }
    public void playAndUnmute(ArrayList<String> curlList, AdvanceTextureView view){
        synchronized (lock) {
            String curl = curlList.get(videoIndex);
            LogUtil.info("[VideoLoaderImpl] playAndUnmute:" + curl + " curr:" + currentUrl);
            if (curl != null && curl.equals(currentUrl)) {
                //异常情况 停止其他已经播放但是没有选中的视频
                if (nextUrl != null) {
                    for (int i = 0; i < playerList.size(); i++) {
                        if (playerList.get(i).url.equals(nextUrl)) {
                            LogUtil.info( "[videoLoaderImpl]stop last played url:" + nextUrl + " url: " + playerList.get(i).url);
                            playerList.get(i).player.stopWithoutRelease();
                            playerList.get(i).player.setAutoPlay(false);
                            if (!glsbMp.containsKey(nextUrl)) {
                                playerList.get(i).player.queryPreloadUrlResult(nextUrl, new GslbResultListener(playerList.get(i).player, nextUrl));
                                LogUtil.info( "[videoLoaderImpl] queryPreloadUrl first url: " + nextUrl);
                            }else {
                                Object session = Objects.requireNonNull(glsbMp.get(nextUrl)).first;
                                NEGslbServerModel model = Objects.requireNonNull(glsbMp.get(nextUrl)).second;
                                playerList.get(i).player.switchWithGslbResult(session, model);
                            }
                            playerList.get(i).url = "";
                            nextUrl = null;
                            break;
                        }
                    }
                }
                LogUtil.info("[VideoLoaderImpl] currenturl:" + currentUrl + " has played");
                return;
            }
            if (curl != null && curl.equals(nextUrl)) {
                //切换url
                lastUrl = currentUrl;
                currentUrl = curl;
                currentSubUrl = null;
                LogUtil.info("[VideoLoaderImpl] change currenturl:" + currentUrl);
                nextUrl = null;
            }
            //暂停上一个播放的视频
            if (lastUrl != null) {
                for (int i = 0; i < playerList.size(); i++) {
                    if (playerList.get(i).url.equals(lastUrl)) {
                        LogUtil.info( "[videoLoaderImpl]stop last playing url:" + lastUrl.substring(Math.max(lastUrl.length() - 8, 0)) + " url: " + playerList.get(i).url.substring(Math.max(playerList.get(i).url.length() - 8, 0)));
                        playerList.get(i).player.stopWithoutRelease();
                        playerList.get(i).url = "";
                        break;
                    }
                }
            }
            //unmute当前播放的视频
            if (currentUrl != null) {
                for (int i = 0; i < playerList.size(); i++) {
                    if (playerList.get(i).url.equals(currentUrl)) {
                        playerList.get(i).player.setMute(false);
                        currentView = view;
                        showParentViews(currentView);
                        currentView.setVisibility(View.VISIBLE);
                        VideoLoaderImpl.getInstance().setupCanvas(currentView);
                        LogUtil.info("[VideoLoaderImpl] current:" + currentUrl + " player:" + i);
                        break;
                    }
                }
            }

        }
    }

    public void renderAndMute(ArrayList<String> curlList, final AdvanceTextureView view){
        synchronized (lock) {
            String curl = curlList.get(videoIndex);
            showParentViews(view);
            view.setVisibility(View.VISIBLE);
            LogUtil.info("[VideoLoaderImpl] renderAndMute: url:" + curl + " curr:" + currentUrl);
            //异常情况 如果nextUrl有值，先停止nextUrl视频
            LogUtil.info("[VideoLoaderImpl] nextUrl:"+ nextUrl);
            if(nextUrl!= null && nextUrl.equals(curl)){
                LogUtil.info("[VideoLoaderImpl] nextUrl: "+ nextUrl + " has played!");
                return;
            }
            if(nextUrl != null){
                for (int i = 0; i < playerList.size(); i++) {
                    if (playerList.get(i).url.equals(nextUrl)) {
                        LogUtil.info( "[videoLoaderImpl]stop last played url:" + nextUrl + " url: " + playerList.get(i).url);
                        playerList.get(i).player.stopWithoutRelease();
                        playerList.get(i).url = "";
                        nextUrl = null;
                        break;
                    }
                }
            }
            //播放当前的地址并mute
            for (int i = 0; i < playerList.size(); i++) {
                if (playerList.get(i).url.equals(curl)) {
                    nextUrl = curl;
                    playerList.get(i).player.setupRenderView(view, VideoScaleMode.FULL);
                    playerList.get(i).player.setMute(true);
                    playerList.get(i).player.startWithoutInit();
                    playerList.get(i).count = 0;
                    LogUtil.info("[renderAndMute]current:" + curl + " player:" + i);
                    break;
                }
            }
        }
    }
    /**
     * 播放器视频准备，需要传递4个url，分别对应当前视频URL，上一个视频URL，下一个视频URL，下下一个视频URL
     */

    public void setLivePlayerURLList(ArrayList<ArrayList<String>> urlList){
        LogUtil.error("[videoLoaderImpl]setLivePlayerURLList! urlList:" + urlList);
        //排除null
        for(int i = 0;i < urlList.size();i++){
            if(urlList.get(i).size() < videoIndex + 1 || urlList.get(i).get(videoIndex) == null){
                LogUtil.info("[videoLoaderImpl]urlList is null");
                return;
            }
        }
        currentUrlList = urlList;
        synchronized (lock) {
            ArrayList<Integer> idlePlayer = new ArrayList<>();
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                ArrayList<String> result = urlList.stream()
                        .filter(list -> list.size() > videoIndex)
                        .map(list -> list.get(videoIndex))
                        .collect(Collectors.toCollection(ArrayList::new));
                HashSet<String> idleUrl = new HashSet<>(result);
                for (int i = 0; i < playerList.size(); i++) {
                    boolean prepared = false;
                    for (String url : result) {
                        //已经prepare的不prepare
                        if (!url.equals("") && playerList.get(i).url.equals(url)) {
                            idleUrl.remove(url);
                            prepared = true;
                            break;
                        }
                    }
                    if (prepared) {
                        LogUtil.info("[videoLoaderImpl]url:" + playerList.get(i).url.substring(Math.max(playerList.get(i).url.length() - 8, 0))
                                + " has prepared, " + "player: " + i);
                        continue;
                    }
                    //不是当前正在播放的url，准备prepare
                    idlePlayer.add(i);
                }
                LogUtil.info("[videoLoaderImpl] currentUrl:" + currentUrl + " ready2prepare:" + idleUrl + " idlePlayer:" + idlePlayer.size());
                for (String url : idleUrl) {
                    if (url.equals(""))
                        continue;
                    //空闲的播放器数量大于0
                    if (idlePlayer.size() > 0) {
                        int index = result.indexOf(url);
                        int playerIndex = idlePlayer.get(0);
                        playerList.get(playerIndex).url = url;
                        playerList.get(playerIndex).urlList = urlList.get(index);
                        playerList.get(playerIndex).player.setAutoPlay(false);
                        if (!glsbMp.containsKey(url)) {
                            playerList.get(playerIndex).player.queryPreloadUrlResult(url, new GslbResultListener(playerList.get(playerIndex).player, url));
                            LogUtil.info("[videoLoaderImpl] queryPreloadUrl first url: " + url);
                        } else {
                            Object session = Objects.requireNonNull(glsbMp.get(url)).first;
                            NEGslbServerModel model = Objects.requireNonNull(glsbMp.get(url)).second;
                            playerList.get(playerIndex).player.switchWithGslbResult(session, model);
                            LogUtil.info("[videoLoaderImpl] switchWithGslbResult url: " + url);
                        }
                        idlePlayer.remove(0);
                        LogUtil.info("[videoLoaderImpl]switchWithGslbResult: " + url.substring(Math.max(url.length() - 8, 0)) + " player: " + playerIndex);
                    }
                }
            }
        }
    }
    @Override
    public void setScrollMode(boolean enabled) {
        isInScrollState = enabled;
    }
    public synchronized void rePreloadOrPlay(NELivePlayer neLivePlayer, final int what, final int extra) {
        String url = neLivePlayer.getCurrentServerModel().url;
        for (Map.Entry<String, Pair<Object,NEGslbServerModel>> entry : glsbMp.entrySet()) {
            String key = entry.getKey();
            Pair<Object,NEGslbServerModel> value = entry.getValue();
            if(value.second.url.equals(neLivePlayer.getCurrentServerModel().url)){
                url = key;
                break;
            }
        }
        if(url != null && !url.equals("")){
            synchronized (lock) {
                LogUtil.info("[videoLoaderImpl] onerror: cur: "+ currentUrl + " " + url);
                //缓冲的url会进行重连 500ms一次，尝试重连10次
                for(int i = 0;i < playerList.size();i++) {
                    LogUtil.info("[onerror] player " + i + " url: " + playerList.get(i).url.equals(url) + " subUrl:" + currentSubUrl);
                    if (playerList.get(i).url.equals(url) || currentSubUrl != null) {
                        if(playerList.get(i).count < 10) {
                            playerList.get(i).stopRefresher();
                            if(playerList.get(i).url.equals(currentUrl) || currentSubUrl != null) {
                                LogUtil.info("[videoLoaderImpl] currentUrl is error");
                                playerList.get(i).player.setAutoPlay(true);
                                playerList.get(i).toggleConnect();
                            }else{
                                LogUtil.info("[onerror] store Url is error");
                                playerList.get(i).player.setAutoPlay(false);
                                playerList.get(i).toggleConnect();
                                playerList.get(i).restartRefresher();
                            }
                            LogUtil.info("[videoLoaderImpl] onerror, player " + i + " " + playerList.get(i).url);
                            break;
                        }else{
                            onError(what, extra);
                            break;
                        }
                    }
                }
            }
        }
    }

    private void onError(final int what, final int extra) {
        if(sink != null){
            sink.onError(what, extra);
        }
    }

    void stopAllRefresher() {
        for(playerInfo player: playerList){
            synchronized (lock) {
                player.stopRefresher();
            }
        }
    }
    void startAllRefresher() {
        for(playerInfo player: playerList){
            synchronized (lock) {
                if (player.url.equals("") || player.url.equals(currentUrl)) {
                    continue;
                }
                player.restartRefresher();
            }
        }
    }

    public String getCurrentUrl() {
        Pair<Object,NEGslbServerModel> obj = glsbMp.get(currentUrl);
        String url = null;
        if(obj != null) {
            url = obj.second.url;
        }
        return url;
    }
    public String getNextUrl() {
        if(nextUrl != null) {
            Pair<Object, NEGslbServerModel> obj = glsbMp.get(nextUrl);
            String url = null;
            if (obj != null) {
                url = obj.second.url;
            }
            return url;
        }else{
            return null;
        }
    }
    public ArrayList<VodPlayer> getAllPlayers() {
        ArrayList<VodPlayer> playerLists = new ArrayList<>();
        for(playerInfo player: playerList){
            playerLists.add(player.player);
        }
        return playerLists;
    }

    public VodPlayer getCurrentPlayer(String url) {
        if(url == null || url.isEmpty())
            return null;
        String targetUrl =  url.substring(url.indexOf("//") + 2);
        for(playerInfo player: playerList){
            if(player.url.equals("")) {
                continue;
            }
            String sourceUrl = player.url.substring(player.url.indexOf("//") + 2);
            if(sourceUrl.equals(targetUrl)){
                return player.player;
            }
        }
        return null;
    }

    public void seekTo(int progress) {
        for(playerInfo player: playerList){
            if(player.url.equals("")) {
                continue;
            }
            if(player.url.equals(currentUrl)){
                long duration = player.player.getDuration();
                long current = duration * progress / 100;
                player.player.seekTo(current);
            }
        }
    }

    public long getDuration() {
        for(playerInfo player: playerList){
            if(player.url.equals("")) {
                continue;
            }
            if(player.url.equals(currentUrl)){
                return player.player.getDuration();
            }
        }
        return 0;
    }

    private static class SingletonHolder {
        public static final VideoLoaderImpl INSTANCE = new VideoLoaderImpl();
    }
    public static VideoLoaderImpl getInstance() {
        return SingletonHolder.INSTANCE;
    }
    public void release() {
        stopAllRefresher();
        for(playerInfo player: playerList){
            synchronized (lock) {
                player.player.registerPlayerObserver(playerObserver, false);
                player.releaseExecutor();
                player.player.stop();
            }
        }
        mhandler = null;
        playerList.clear();
    }
    private VideoOptions configOptions(){
        VideoOptions options = new VideoOptions();
        options.bufferStrategy = VideoBufferStrategy.DELAY_PULL_UP;
        options.bufferingStopStrategy = PlayerBufferingStopStrategy.ALL_STREAMS_REQUIRED;
        options.hardwareDecode = false;
        /**
         * isPlayLongTimeBackground 控制退到后台或者锁屏时是否继续播放，开发者可根据实际情况灵活开发,我们的示例逻辑如下：
         * 使用软件解码：
         * isPlayLongTimeBackground 为 false 时，直播进入后台停止播放，进入前台重新拉流播放
         * isPlayLongTimeBackground 为 true 时，直播进入后台不做处理，继续播放,
         *
         * 使用硬件解码：
         * 直播进入后台停止播放，进入前台重新拉流播放
         */
        options.isPlayLongTimeBackground = false;
        return options;
    }

    public void clearUrl() {
        synchronized (lock) {
            LogUtil.info( "[videoLoaderImpl] clearUrl lastUrl:" + lastUrl + "currentUrl:" + currentUrl + "nexturl:" + nextUrl);
            lastUrl = currentUrl;
            currentUrl = null;
            currentUrlList = null;
            currentSubUrl = null;
            nextUrl = null;
        }
    }
    private static void showParentViews(View view) {
        if (view != null) {
            if (view.getVisibility() != View.VISIBLE) {
                view.setVisibility(View.VISIBLE);
            }
            if (view.getParent() instanceof View) {
                showParentViews((View)view.getParent());
            }
        }
    }
    private void setupCanvas(AdvanceTextureView view) {
        setupCanvasInner(view);
        mhandler.postDelayed(setUpCanvasRunnable, 400);
    }

    private Runnable setUpCanvasRunnable = new Runnable() {
        @Override
        public void run() {
            synchronized (lock) {
                if (currentUrl != null) {
                    for (int i = 0; i < playerList.size(); i++) {
                        if (playerList.get(i).url.equals(currentUrl) && nextUrl == null) {
                            playerList.get(i).player.reSetupRenderView();
                            break;
                        }
                    }
                }
            }
        }
    };
    private void setupCanvasInner(AdvanceTextureView view) {
        if(currentUrl != null){
            for(int i = 0;i < playerList.size();i++) {
                if(playerList.get(i).url.equals(currentUrl) && nextUrl == null) {
                    playerList.get(i).player.setupRenderView(view, VideoScaleMode.FULL);
                    break;
                }
            }
        }
    }

    void glsbResultAdd(String originUrl, Object o,NEGslbServerModel model){
        glsbMp.put(originUrl, new Pair<>(o, model));
    }
    public int getMode(){
        return mMode;
    }
    private class playerInfo{
        public String url;
        public ArrayList<String> urlList;
        public VodPlayer player;
        private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
        private ScheduledFuture<?> scheduledFuture = null;
        private boolean isRefresherStart = false;
        public long count = 0;
        Runnable task = new Runnable() {
            @Override
            public void run() {
                if(url.equals(""))
                    return;
                player.stopWithoutRelease();
                player.setAutoPlay(false);
                if (!glsbMp.containsKey(url)) {
                    player.queryPreloadUrlResult(url, new GslbResultListener(player, url));
                    LogUtil.info( "[videoLoaderImpl] queryPreloadUrl first url: " + url);
                }else {
                    Object session = Objects.requireNonNull(glsbMp.get(url)).first;
                    NEGslbServerModel model = Objects.requireNonNull(glsbMp.get(url)).second;
                    player.switchWithGslbResult(session, model);
                }
                LogUtil.info( "[videoLoaderImpl]refresh:" + url.substring(Math.max(url.length() - 8, 0)));
            }
        };
         playerInfo(String u, VodPlayer p){
             url = u;
             player = p;
         }
        public void stopRefresher() {
            if (scheduledFuture != null) {
                scheduledFuture.cancel(true);
                scheduledFuture = null;
                isRefresherStart = false;
            }

        }
        public void restartRefresher() {
            synchronized (lock) {
                startTimer();
            }
        }
        public void releaseExecutor() {
            executor.shutdown();
            isRefresherStart = false;
        }
        private void startTimer() {
             if(isRefresherStart)
                 return;
             scheduledFuture = executor.scheduleWithFixedDelay(task, 15, 15, TimeUnit.SECONDS);
            isRefresherStart = true;
        }
        public void toggleConnect() {
            executor.schedule(new Runnable() {
                @Override
                public void run() {
                    count++;
                    if(count > 10) {
                        LogUtil.info("[videoLoaderImpl] current url: " + currentUrl.substring(Math.max(currentUrl.length() - 8, 0)) + "     reswitch:  " + url.substring(Math.max(url.length() - 8, 0)));
                        return;
                    }
                    if (!glsbMp.containsKey(url)) {
                        player.queryPreloadUrlResult(url, new GslbResultListener(player, url));
                        LogUtil.info( "[videoLoaderImpl] queryPreloadUrl first url: " + url);
                    }else {
                        Object session = Objects.requireNonNull(glsbMp.get(url)).first;
                        NEGslbServerModel model = Objects.requireNonNull(glsbMp.get(url)).second;
                        player.switchWithGslbResult(session, model);
                    }
                }
            },200, TimeUnit.MILLISECONDS);
        }

    };

}
